package phase1.main;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.List;
import java.util.Scanner;

import phase1.part1.Driver;
import phase1.part2.DFAFileWriter;
import phase1.part2.NFAFileReader;
import phase1.part3.InputFileReader.FileFormatException;
import phase1.part3.TableWalker;
import phase1.part3.Token;

/**
 * 
 * 
 * @author John Girata
 * @version Nov 13, 2012./
 */
public class Main {
	private static final String TEMP_DIR = "tmp/";
	private static final String PART1_OUTPUT = "part1-output.txt";
	private static final String PART2_OUTPUT = "part2-output.txt";

	public static void main(String[] args) throws Exception {
		if (!checkArgs(args)) {
			return;
		}

		String spec = args[0];
		String input = args[1];
		String output = args[2];

		makeFiles(output);

		part1(spec, TEMP_DIR + PART1_OUTPUT);
		part2(TEMP_DIR + PART1_OUTPUT, TEMP_DIR + PART2_OUTPUT);
		part3(input, TEMP_DIR + PART2_OUTPUT, new PrintStream(output));
	}

	public static boolean checkArgs(String[] args) {
		if (args.length == 3) {
			return true;
		}

		System.out.println("Usage: java -jar Phase1.jar spec input output");
		System.out.println("    spec      the language spec filename");
		System.out.println("    input     the input filename");
		System.out.println("    output    the output filename");

		return false;
	}

	/**
	 * Creates the output file and temp directory, if they do not already exist.
	 * 
	 * @param output
	 *            The output filename
	 * @throws IOException
	 *             If the output file's parent directory does not exist
	 */
	private static void makeFiles(String output) throws IOException {
		File file = new File(TEMP_DIR);

		if (!file.exists()) {
			file.mkdir();
		}

		// Creates the file if it does not already exist
		try {
			new File(output).createNewFile();
		} catch (IOException e) {
			throw new IOException(
					"Output file's parent directory does not exist", e);
		}
	}
	
	private static void part1(String spec, String nfa) throws FileNotFoundException {
//		new SpecFileReader(spec, nfa);
		Driver.buildNFA(spec, nfa);
	}

	/**
	 * Executes part 2. This consists of converting the NFA generated in part 1
	 * into a DFA.
	 * 
	 * @param nfa
	 *            The NFA file (result of part 1)
	 * @param dfa
	 *            The DFA file (result of part 2)
	 * @throws FileNotFoundException
	 *             If either file does not exist
	 * @throws FileFormatException
	 *             If the NFA file is not properly formatted
	 * @throws IOException
	 *             If an error occurs reading or writing a file
	 */
	private static void part2(String nfa, String dfa)
			throws FileNotFoundException, NFAFileReader.FileFormatException,
			IOException {
		new DFAFileWriter(nfa, dfa);
	}

	/**
	 * Executes part 3. This consists of parsing the input file into tokens and
	 * writing them to a file.
	 * 
	 * @param input
	 *            The input file to parse
	 * @param dfa
	 *            The DFA file (result of part 2)
	 * @param out
	 *            The stream to which the output should be sent
	 * @throws FileNotFoundException
	 *             If the input file or DFA file does not exist
	 * @throws FileFormatException
	 *             If the DFA file is not properly formatted
	 */
	private static void part3(String input, String dfa, PrintStream out)
			throws FileNotFoundException, FileFormatException {
		TableWalker walker = new TableWalker(dfa);

		Scanner scanner = new Scanner(new File(input));
		StringBuilder builder = new StringBuilder();

		while (scanner.hasNext()) {
			builder.append(scanner.nextLine());
			builder.append("\n");
		}

		List<Token> tokens = walker.process(builder.toString());

		for (Token token : tokens) {
			out.println(token.getType() + " " + token.getValue());
		}
	}
}
